﻿namespace Site2AppWP8
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.IO.IsolatedStorage;
    using System.Linq;
    using System.Net;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls.Primitives;
    using System.Windows.Navigation;
    using System.Windows.Threading;
    using Microsoft.Phone.Controls;
    using Microsoft.Phone.Scheduler;
    using Microsoft.Phone.Shell;
    using Microsoft.Phone.Tasks;
    using Microsoft.Xna.Framework;
    using Site2AppWP8.Config;
    using Site2AppWP8.IconEnum;
    using Site2AppWP8.Modules;
    using Site2AppWP8.Resources;
    using Windows.Storage;
    using Newtonsoft.Json;
    using Site2AppWP8.Template.XHR;
    using Site2AppWP8.Template;

    public partial class MainPage : PhoneApplicationPage
    {
        private const string PeriodicTaskName = "PeriodicAgent";

        #region File and Media and Launch Extensions
        // If it's one of these, we'll need to launch the media player
        // from http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj207065(v=vs.105).aspx
        private static string[] mediaExtensions = 
        {
                ".3gp",
                ".3g2",
                ".3gpp",
                ".3gpp2",
                ".aac",
                ".aetx",
                ".asf",
                ".avi",
                ".m1v",
                ".m2v",
                ".m4a",
                ".m4r",
                ".m4v",
                ".mkv",
                ".mov",
                ".mp3",
                ".mp4",
                ".mpe",
                ".mpeg",
                ".mpg",
                ".qcp",
                ".wav",
                ".wdp",
                ".wma",
                ".wmv"
        };

        // If it's one of these, we'll need to launch the appropriate handler
        // from http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj207065(v=vs.105).aspx
        private static string[] launchExtensions = 
        {
                ".rtf",
                ".tif",
                ".tiff",
                ".one",
                ".onetoc2",
                ".doc",
                ".docm",
                ".docx",
                ".dot",
                ".dotm",
                ".dotx",
                ".pdf",
                ".pptx",
                ".pptm",
                ".potx",
                ".potm",
                ".ppam",
                ".ppsx",
                ".ppsm",
                ".ppt",
                ".pps",
                ".xls",
                ".xlm",
                ".xlt",
                ".xlsx",
                ".xlsm",
                ".xltx",
                ".xltm",
                ".xlsb",
                ".xlam",
                ".xll",
                ".cer",
                ".hdp",
                ".ico",
                ".icon",
                ".jxr",
                ".p7b",
                ".pem",
                ".txt",
                ".url",
                ".vcf",
                ".xap",
                ".xht",
                ".xsl",
                ".zip"
        };

        // IE will handle these protocols for us
        private static string[] launchProtocols = 
        {
                "callto",
                "mailto",
                "ms-",
                "onenote",
                "wallet",
                "zune"
        };

        // We can skip a bunch of logic if we see these common extensions
        private static string[] bypassList = 
        {
                ".com",
                ".htm",
                ".html",
                ".asp",
                ".aspx",
                ".js",
                ".xml"
        };
        #endregion

        // This is the original orientation state
        private PageOrientation from = PageOrientation.PortraitUp;

        // This is the new orientation state
        private PageOrientation to;
        
        // Overlay
        private Popup popup;

        private ProgressOverlay progressOverlay;
        private WebDialogOverlay webDialogOverlay;

        private Uri nonHttpUri;

        // IconEnumHelper points to the appropriate files for enum-based
        //   app bar construction
        private IconEnumHelper iconEnums = new IconEnumHelper();

        // Serialize URL into IsoStorage on deactivation for Fast App Resume
        private Uri currentUrl;
        private IsolatedStorageSettings userSettings = IsolatedStorageSettings.ApplicationSettings;

        // Variables for our periodic task to update the lock screen
        private PeriodicTask periodicTask;

        private OfflineModule offlineModule;

        private WebConfig webConfig;

        private DispatcherTimer loadCompleteSimulationTimer;
        private int loadCompleteSimulationCounter;
        private bool isDomLoadedHandled = false;

        private bool _activeNavigation = false;
        private bool _navigationAtDeactivation = false;

        private string PageTitle = "";

        // Constructor
        public MainPage()
        {
            this.InitializeComponent();

            this.Browser.NavigationFailed += Browser_NavigationFailed;

            // Overlay
            this.popup = new Popup();
            this.LayoutRoot.Children.Add(this.popup);

            this.progressOverlay = new ProgressOverlay(this);
            this.webDialogOverlay = new WebDialogOverlay(this);

            this.webConfig = ((App)Application.Current).WebConfig;

            // Handle orientation changes
            this.OrientationChanged += this.MainPage_OrientationChanged;

            PhoneApplicationService.Current.Activated += this.Current_Activated;
            PhoneApplicationService.Current.Deactivated += this.Current_Deactivated;
            PhoneApplicationService.Current.Closing += this.Current_Closing;


            try
            {
                if (this.userSettings.Contains("deactivatedUrl"))
                {
                    this.currentUrl = (Uri)this.userSettings["deactivatedUrl"];
                }
            }
            catch (KeyNotFoundException)
            {
            }
            catch (Exception exn)
            {
                Debug.WriteLine(exn.ToString());
            }

            this.LoadModules();
            this.StartPeriodicAgent();
        }

        #region Overlays
        public void ShowProgresBarOverlay()
        {
            this.ShowOverlay(this.progressOverlay);
        }

        public void ShowOverlay(UIElement overlay)
        {
            this.popup.Child = overlay;
            this.popup.IsOpen = true;

            this.Browser.Opacity = 0.0;
        }

        public void HideOverlay()
        {
            this.popup.Child = null;
            this.popup.IsOpen = false;

            this.Browser.Opacity = 1.0;
        }
        #endregion

        protected override async void OnNavigatedTo(NavigationEventArgs e)
        {
            await this.EnsureWebConfigIsLoaded();

            if (this.webConfig != null)
            {
                if (this.ApplicationBar == null)
                {
                    this.BuildLocalizedApplicationBar();
                }
            }


            // Grab deeplink url if available 
            if (e.Uri.OriginalString.Contains("StartURL="))
            {
                string originalUrl = e.Uri.OriginalString;

                int i = originalUrl.IndexOf("StartURL=") + 9;

                string deepLink = originalUrl.Substring(i);

                try
                {
                    this.currentUrl = new Uri(deepLink);
                }
                catch
                {
                    this.currentUrl = this.webConfig.GetBaseUrl();
                }
            }



            if (e.NavigationMode == NavigationMode.Back && this.Browser.Source != null)
            {
                // Navigated back from backstack. By default, use the current page of the browser

                // Add code here
                // ...
            }
            else if (e.NavigationMode == NavigationMode.Reset)
            {
                // Resuming the app. By default, nothing needs to be done

                // Add code here
                // ...
            }
            else if (e.NavigationMode == NavigationMode.Refresh && this.Browser.Source != null)
            {
                // Refresh the content of the page. By default, use the current page of the browser

                // Add code here
                // ...
            }
            else if (this.currentUrl != null && e.NavigationMode == NavigationMode.New)
            {
                this.Browser.Navigate(this.currentUrl);
            }
            else
            {
                // Else, navigate to the base URL
                Browser.Navigate(this.webConfig.GetBaseUrl());
            }
        }

        protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
        {
            base.OnBackKeyPress(e);

            // If a popup is open (and it is not the progress bar) then close the popup
            if (this.popup.IsOpen && !(this.popup.Child is ProgressOverlay))
            {
                this.HideOverlay();
                e.Cancel = true;
                return;
            }

            // ... navigate through the browser's history
            if (this.Browser.CanGoBack)
            {
                this.Browser.GoBack();
                e.Cancel = true; // if we skip this then the app will terminate.
            }
        }

        private async Task LoadConfig()
        {
            // Get a file from the installation folder with the ms-appx URI scheme.
            var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Config/config.json"));

            using (Stream stream = await file.OpenStreamForReadAsync())
            {
                using (StreamReader sr = new StreamReader(stream))
                {
                    string configJSON = sr.ReadToEnd();
                    this.webConfig = WebConfig.CreateConfig(configJSON);
                }
            }
        }

        private async void LoadModules()
        {
            await this.EnsureWebConfigIsLoaded();

            if (this.webConfig.Logging != null && this.webConfig.Logging.IsEnabled)
            {
                this.Browser.Navigated += LogModule.InjectSpys;
                this.Browser.ScriptNotify += LogModule.CheckForMessages;
            }

            this.offlineModule = new OfflineModule(this.webConfig, this.Browser, this);
        }

        private async void StartPeriodicAgent()
        {
            await this.EnsureWebConfigIsLoaded();

            if (this.webConfig.LiveTile.IsEnabled)
            {
                this.periodicTask = ScheduledActionService.Find(PeriodicTaskName) as PeriodicTask;
                IsolatedStorageSettings.ApplicationSettings["TilePollFeed"] = this.webConfig.LiveTile.TilePollFeed;
                IsolatedStorageSettings.ApplicationSettings["ShowImage"] = this.webConfig.LiveTile.ShowImage;
                IsolatedStorageSettings.ApplicationSettings["TileType"] = this.webConfig.LiveTile.TileType;
                IsolatedStorageSettings.ApplicationSettings.Save();

                // is old task running, remove it
                this.periodicTask = ScheduledActionService.Find(PeriodicTaskName) as PeriodicTask;

                if (this.periodicTask != null)
                {
                    try
                    {
                        ScheduledActionService.Remove(PeriodicTaskName);
                    }
                    catch (Exception)
                    {
                    }
                }

                // create a new task
                this.periodicTask = new PeriodicTask(PeriodicTaskName);

                // load description from localized strings
                this.periodicTask.Description = "Periodic task for updating the live tile for Site2AppWP8.";

                // set expiration days
                this.periodicTask.ExpirationTime = DateTime.Now.AddDays(14);

                try
                {
                    // add thas to scheduled action service
                    ScheduledActionService.Add(this.periodicTask);

                    // debug, so run in every 30 secs
#if(DEBUG)
                    ScheduledActionService.LaunchForTest(PeriodicTaskName, TimeSpan.FromSeconds(10));
                    System.Diagnostics.Debug.WriteLine("Periodic task is started: " + PeriodicTaskName);
#endif
                }
                catch (InvalidOperationException exception)
                {
                    if (exception.Message.Contains("BNS Error: The action is disabled"))
                    {
                        // load error text from localized strings
                        MessageBox.Show("Background agents for this application have been disabled by the user.");
                    }

                    if (exception.Message.Contains("BNS Error: The maximum number of ScheduledActions of this type have already been added."))
                    {
                        // No user action required. The system prompts the user when the hard limit of periodic tasks has been reached.
                    }
                }
                catch (SchedulerServiceException)
                {
                    // No user action required.
                }
            }
        }

        private async Task EnsureWebConfigIsLoaded()
        {
            if (this.webConfig == null)
            {
                var currentApp = (App)Application.Current;
                if (currentApp.WebConfig == null)
                {
                    await currentApp.ManualConfigLoad();
                }

                this.webConfig = currentApp.WebConfig;
            }
        }

        #region Lifecycle Management (Fast App Resume)

        private void Current_Activated(object sender, ActivatedEventArgs e)
        {
            if (this.userSettings.Contains("deactivatedUrl"))
            {
                this.currentUrl = (Uri)this.userSettings["deactivatedUrl"];
            }
        }

        private void Current_Closing(object sender, ClosingEventArgs e)
        {
            // Clears the last url in storage
            if (this.userSettings.Contains("deactivatedUrl"))
            {
                this.userSettings.Remove("deactivatedUrl");
            }
        }

        private void Current_Deactivated(object sender, DeactivatedEventArgs e)
        {
            if (this.userSettings.Contains("deactivatedUrl"))
            {
                this.userSettings.Remove("deactivatedUrl");
            }

            // Persist last url in storage
            this.userSettings.Add("deactivatedUrl", this.currentUrl);

            if (_activeNavigation)
            {
                _navigationAtDeactivation = true;
            }
            else
            {
                _navigationAtDeactivation = false;
            }

        }
        #endregion

        #region Application Bar Construction & Event Handlers
        // ApplicationBar
        private void BuildLocalizedApplicationBar()
        {
            // Create an ApplicationBar whenever an ApplicationBarIconButton or ApplicationBarMenuItem is enabled
            // We also need the ApplicationBar for sharing
            if ((this.webConfig.NavBar != null && this.webConfig.NavBar.IsEnabled) ||
                (this.webConfig.AppBar != null && this.webConfig.AppBar.IsEnabled) ||
                (this.webConfig.Share != null && this.webConfig.Share.IsEnabled))
            {
                // Set the page's ApplicationBar to a new instance of ApplicationBar.
                this.ApplicationBar = new ApplicationBar();

                if (this.webConfig.AppBar.IsForegroundColorDefined)
                {
                    this.ApplicationBar.ForegroundColor = this.webConfig.AppBar.ForegroundColor;
                }

                if (this.webConfig.AppBar.IsBackgroundColorDefined)
                {
                    this.ApplicationBar.BackgroundColor = this.webConfig.AppBar.BackgroundColor;
                }

                if (this.webConfig.AppBar != null && !this.webConfig.AppBar.IsEnabled &&
                    this.webConfig.Share != null && !this.webConfig.Share.IsEnabled)
                {
                    this.ApplicationBar.Mode = ApplicationBarMode.Minimized;
                }
                else
                {
                    // Set the size of the browser control
                    this.Browser.Height = Application.Current.Host.Content.ActualHeight - this.ApplicationBar.DefaultSize;

                    if (this.webConfig.AppBar != null && this.webConfig.AppBar.Buttons != null)
                    {
                        // Make sure the number of buttons does not exceeds 4
                        Debug.Assert(this.webConfig.AppBar.Buttons.Count > 4, "The number of buttons exceeds 4!");

                        foreach (BarButton bb in this.webConfig.AppBar.Buttons)
                        {
                            // ApplicationBarIconButton appBarButton = new ApplicationBarIconButton(new Uri(bb.Icon, UriKind.Relative));
                            ApplicationBarIconButton appBarButton = new ApplicationBarIconButton();

                            if (!string.IsNullOrEmpty(bb.Icon) && this.iconEnums.IsIconAvailable(bb.Icon))
                            {
                                appBarButton.IconUri = this.iconEnums.GetIconUri(bb.Icon);
                            }
                            else
                            {
                                appBarButton.IconUri = bb.IconUri;
                            }

                            appBarButton.Text = bb.Label;
                            appBarButton.Click += this.AppBarButton_Click;
                            this.ApplicationBar.Buttons.Add(appBarButton);
                        }
                    }


                    // If Pinning is enabled we put it in the ApplicationBar buttons if there are less than 4 buttons configured
                    // else we move it to the ApplicationBar menu

                    try
                    {
                        if (this.webConfig.Pin != null && this.webConfig.Pin.IsEnabled)
                        {
                            if (ApplicationBar.Buttons.Count < 4)
                            {
                                ApplicationBarIconButton appBarButtonPin = new ApplicationBarIconButton(new Uri("/Assets/AppBar/pin.png", UriKind.Relative));
                                appBarButtonPin.Text = this.webConfig.Pin.ButtonText;
                                appBarButtonPin.Click += this.AppBarButton_Click;
                                ApplicationBar.Buttons.Add(appBarButtonPin);
                            }
                            else
                            {
                                ApplicationBarMenuItem appBarButtonPin = new ApplicationBarMenuItem();
                                appBarButtonPin.Text = this.webConfig.Pin.ButtonText;
                                appBarButtonPin.Click += this.AppBarMenuItem_Click;
                                ApplicationBar.Buttons.Add(appBarButtonPin);
                            }
                        }
                    }
                    catch (Exception)
                    {
                        Debug.WriteLine("Total number of ApplicationBar buttons exceeded maximum");
                    }

                    // If Share is enabled we put it in the ApplicationBar buttons if there are less than 4 buttons configured
                    // else we move it to the ApplicationBar menu
                    try
                    {
                        if (this.webConfig.Share != null && this.webConfig.Share.IsEnabled)
                        {
                            if (this.ApplicationBar.Buttons.Count < 4)
                            {
                                ApplicationBarIconButton appBarButtonShare = new ApplicationBarIconButton(new Uri("/Assets/AppBar/share2.png", UriKind.Relative));
                                appBarButtonShare.Text = this.webConfig.Share.Title;
                                appBarButtonShare.Click += this.AppBarButton_Click;
                                this.ApplicationBar.Buttons.Add(appBarButtonShare);
                            }
                            else
                            {
                                ApplicationBarMenuItem appBarMenuShare = new ApplicationBarMenuItem();
                                appBarMenuShare.Text = this.webConfig.Share.Title;
                                appBarMenuShare.Click += this.AppBarMenuItem_Click;
                                this.ApplicationBar.MenuItems.Add(appBarMenuShare);
                            }
                        }
                    }
                    catch (Exception)
                    {
                        Debug.WriteLine("Total number of ApplicationBar buttons exceeded maximum");
                    }
                }

                if (this.webConfig.NavBar != null && this.webConfig.NavBar.IsEnabled)
                {
                    if (this.webConfig.NavBar != null && this.webConfig.NavBar.Buttons != null)
                    {
                        foreach (BarButton bb in this.webConfig.NavBar.Buttons)
                        {
                            ApplicationBarMenuItem appBarMenuItem = new ApplicationBarMenuItem();
                            appBarMenuItem.Text = bb.Label;
                            appBarMenuItem.Click += this.AppBarMenuItem_Click;
                            this.ApplicationBar.MenuItems.Add(appBarMenuItem);
                        }
                    }

                    // Settings Url/Title page
                    if (this.webConfig.Settings != null &&
                        (!string.IsNullOrEmpty(this.webConfig.Settings.SettingsUrlString) ||
                        !string.IsNullOrEmpty(this.webConfig.Settings.Title)))
                    {
                        ApplicationBarMenuItem appBarMenuItemHelp = new ApplicationBarMenuItem(AppResources.Help);
                        appBarMenuItemHelp.Click += this.AppBarMenuItemHelp_Click;
                        this.ApplicationBar.MenuItems.Add(appBarMenuItemHelp);
                    }

                    if (this.webConfig.Settings != null &&
                        (!string.IsNullOrEmpty(this.webConfig.Settings.FeedbackEmail) ||
                        !string.IsNullOrEmpty(this.webConfig.Settings.FeedbackUrl)))
                    {
                        // Feedback
                        ApplicationBarMenuItem appBarMenuItemReport = new ApplicationBarMenuItem(AppResources.ReportBroken);
                        appBarMenuItemReport.Click += this.AppBarMenuItemReport_Click;
                        this.ApplicationBar.MenuItems.Add(appBarMenuItemReport);
                    }

                    if (this.webConfig.Settings != null &&
                        !string.IsNullOrEmpty(this.webConfig.Settings.PrivacyUrlString))
                    {
                        // Privacy
                        ApplicationBarMenuItem appBarMenuItemPrivacy = new ApplicationBarMenuItem(AppResources.Privacy);
                        appBarMenuItemPrivacy.Click += this.AppBarMenuItemPrivacy_Click;
                        this.ApplicationBar.MenuItems.Add(appBarMenuItemPrivacy);
                    }
                }
            }
        }

        private void AppBarMenuItemPrivacy_Click(object sender, EventArgs e)
        {
            this.Browser.Navigate(this.webConfig.Settings.PrivacyUrl);
        }

        private void AppBarMenuItem_Click(object sender, EventArgs e)
        {
            ApplicationBarMenuItem item = (ApplicationBarMenuItem)sender;

            // if the user pressed the share menu item
            if (this.webConfig.Share != null && this.webConfig.Share.Title == item.Text)
            {
                this.ShareAction();
                return;
            }

            if (this.webConfig.Pin != null && this.webConfig.Pin.ButtonText == item.Text)
            {
                this.PinAction((ApplicationBarIconButton)sender);
                return;
            }

            if (this.webConfig.NavBar != null && this.webConfig.NavBar.Buttons != null)
            {
                foreach (BarButton bb in this.webConfig.NavBar.Buttons)
                {
                    if (bb.Label == item.Text)
                    {
                        if (Uri.IsWellFormedUriString(bb.ActionString, UriKind.Absolute))
                        {
                            Browser.Navigate(bb.Action);
                            break;
                        }
                        else
                        {
                            if (bb.ActionString.Equals("refresh") && this.currentUrl != null)
                            {
                                this.Browser.Navigate(this.currentUrl);
                                break;
                            }

                            if (bb.ActionString.Equals("home") || bb.ActionString.Equals("refresh"))
                            {
                                this.Browser.Navigate(this.webConfig.GetBaseUrl());
                                break;
                            }
                        }
                    }
                }
            }
        }

        private void AppBarButton_Click(object sender, EventArgs e)
        {
            ApplicationBarIconButton button = (ApplicationBarIconButton)sender;

            if (this.webConfig.Share != null && this.webConfig.Share.Title == button.Text)
            {
                this.ShareAction();
                return;
            }

            if (this.webConfig.Pin != null && this.webConfig.Pin.ButtonText == button.Text)
            {
                this.PinAction((ApplicationBarIconButton)sender);
                return;
            }

            if (this.webConfig.AppBar != null && this.webConfig.AppBar.Buttons != null)
            {
                foreach (BarButton bb in this.webConfig.AppBar.Buttons)
                {
                    if (bb.Label == button.Text)
                    {
                        if (Uri.IsWellFormedUriString(bb.ActionString, UriKind.Absolute))
                        {
                            this.Browser.Navigate(bb.Action);
                            break;
                        }
                        else
                        {
                            if (bb.ActionString.Equals("refresh") && this.currentUrl != null)
                            {
                                this.Browser.Navigate(this.currentUrl);
                                break;
                            }

                            if (bb.ActionString.Equals("home") || bb.ActionString.Equals("refresh"))
                            {
                                this.Browser.Navigate(this.webConfig.GetBaseUrl());
                                break;
                            }
                        }
                    }
                }
            }
        }

        private void AppBarMenuItemReport_Click(object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(this.webConfig.Settings.FeedbackEmail))
            {
                string body = "Windows Phone " + System.Environment.OSVersion.Version.Major.ToString() + "." + System.Environment.OSVersion.Version.Minor.ToString();
                EmailComposeTask ect = new EmailComposeTask();
                ect.Subject = this.webConfig.Settings.FeedbackSubject;
                if (this.currentUrl != null)
                {
                    ect.Body = body + " : " + this.currentUrl.OriginalString;
                }

                ect.To = this.webConfig.Settings.FeedbackEmail;
                ect.Show();
            }
            else if (!string.IsNullOrEmpty(this.webConfig.Settings.FeedbackUrl))
            {
                if (Uri.IsWellFormedUriString(this.webConfig.Settings.FeedbackUrl, UriKind.Absolute))
                {
                    try
                    {
                        this.Browser.Navigate(new Uri(this.webConfig.Settings.FeedbackUrl));
                    }
                    catch (Exception exn)
                    {
                        Debug.WriteLine(exn.ToString());
                    }
                }
            }
        }

        private void AppBarMenuItemHelp_Click(object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(this.webConfig.Settings.SettingsUrlString))
            {
                Browser.Navigate(this.webConfig.Settings.SettingsUrl);
            }
            else
            {
                NavigationService.Navigate(new Uri("/AboutPage.xaml", UriKind.Relative));
            }
        }

        private void ShareAction()
        {
            var linkUrl = (this.currentUrl != null) ? this.currentUrl.OriginalString : this.webConfig.GetBaseUrl().OriginalString;
            this.NavigationService.Navigate(new Uri("/SharePage.xaml?Message=" + HttpUtility.UrlEncode(this.webConfig.Share.Message) + "&LinkURL=" + linkUrl, UriKind.Relative));
        }

        void PinAction(ApplicationBarIconButton appBarButton)
        {

            // Get document title for the title of the pinned tile
            string html = this.Browser.SaveToString();
            int titleStart = 0;
            int titleEnd = 0;
            string title = "";

            if (html.IndexOf("<title>") != -1)
            {
                titleStart = html.IndexOf("<title>") + 7;
            }
            else if (html.IndexOf("<TITLE>") != -1)
            {
                titleStart = html.IndexOf("<TITLE>") + 7;
            }
            else
            {
                titleStart = 0;
            }

            if (html.IndexOf("</title>") != -1)
            {
                titleEnd = html.IndexOf("</title>");
            }
            else if (html.IndexOf("</TITLE>") != -1)
            {
                titleEnd = html.IndexOf("</TITLE>");
            }
            else
            {
                titleEnd = 0;
            }


            if (titleStart > 0 && titleEnd > 0)
            {
                title = html.Substring(titleStart, titleEnd - titleStart);
            }
            

            // Pin to start
            StandardTileData std = new StandardTileData();
            std.BackgroundImage = new Uri(this.webConfig.Pin.SquareImage, UriKind.Relative);
            std.Title = title;

            var linkUrl = (this.currentUrl != null) ? this.currentUrl.OriginalString : this.webConfig.GetBaseUrl().OriginalString;
            //std.Title = linkUrl;
            ShellTile.Create(new Uri("/MainPage.xaml?StartURL=" + linkUrl, UriKind.Relative), std);
            appBarButton.IsEnabled = false;
        }

        #endregion

        #region Orientation Changes
        // Handle orientation changes
        private void MainPage_OrientationChanged(object sender, OrientationChangedEventArgs e)
        {
            this.to = e.Orientation;
            if (this.from == PageOrientation.None)
            {
                this.from = this.to;
            }

            switch (this.from)
            {
                case PageOrientation.PortraitUp:
                    switch (this.to)
                    {
                        case PageOrientation.LandscapeLeft:
                            this.RotateAnimation.From = -90;
                            break;
                        case PageOrientation.LandscapeRight:
                            this.RotateAnimation.From = 90;
                            break;
                        case PageOrientation.PortraitDown:
                            this.RotateAnimation.From = 180;
                            break;
                    }

                    break;
                case PageOrientation.LandscapeLeft:
                    switch (this.to)
                    {
                        case PageOrientation.PortraitUp:
                            this.RotateAnimation.From = 90;
                            break;
                        case PageOrientation.PortraitDown:
                            this.RotateAnimation.From = -90;
                            break;
                        case PageOrientation.LandscapeRight:
                            this.RotateAnimation.From = 180;
                            break;
                    }

                    break;
                case PageOrientation.LandscapeRight:
                    switch (this.to)
                    {
                        case PageOrientation.PortraitUp:
                            this.RotateAnimation.From = -90;
                            break;
                        case PageOrientation.PortraitDown:
                            this.RotateAnimation.From = 90;
                            break;
                        case PageOrientation.LandscapeLeft:
                            this.RotateAnimation.From = 180;
                            break;
                    }

                    break;
                case PageOrientation.PortraitDown:
                    switch (this.to)
                    {
                        case PageOrientation.PortraitUp:
                            this.RotateAnimation.From = 180;
                            break;
                        case PageOrientation.LandscapeRight:
                            this.RotateAnimation.From = -90;
                            break;
                        case PageOrientation.LandscapeLeft:
                            this.RotateAnimation.From = 90;
                            break;
                    }

                    break;
            }

            this.RotateAnimation.To = 0;
            this.RotateStoryboard.Begin();
            this.from = this.to;
        }
        #endregion

        #region Navigation, Browser Load and Back Button 
        private void Browser_Navigating(object sender, NavigatingEventArgs e)
        {
            _activeNavigation = true;

            this.isDomLoadedHandled = false;

            if (RedirectModule.ApplyRedirectRules(this.Browser, e, this.webConfig))
            {
                return;
            }

            // Before anything, check to ensure there is a network connection
            if (!this.offlineModule.VerifyNetworkConnected())
            {
                e.Cancel = true;
                return;
            }

            //build a temp 'absolute' uri in case we only have a uri for local relative content (as some later calls break otherwise)
            Uri tempUri;
            if (e.Uri.IsAbsoluteUri)
            {
                tempUri = e.Uri;
            }
            else
            {
                tempUri = new Uri(new Uri("appdata:/"), e.Uri);
            }

            // Check for a special protocol. If there is, the browser control will handle it so don't show the progress bar.
            if (tempUri.Scheme == "javascript")
            {
                return;
            }

            bool customProtocol = false;
            foreach (string s in launchProtocols)
            {
                if (tempUri.OriginalString.StartsWith(s, StringComparison.OrdinalIgnoreCase))
                {
                    customProtocol = true;
                    break;
                }
            }

            if (!customProtocol)
            {
                // If there's no special protocol...
                // Do a quick check for the common case - if there's no file extension in the URL...
                if (tempUri.Segments.Length > 0)
                {
                    // No file specified
                    if (!tempUri.Segments[tempUri.Segments.Length - 1].Contains('.'))
                    {
                        // Browse and show the progress bar
                        this.ShowProgresBarOverlay();
                    }

                    // else // Otherwise check for file types
                    {
                        bool handledExtension = false;   // used when URL points to a common file type - skip the other checks
                        bool mediaFileType = false;  // used when URL points to a media file type - skip the other checks

                        // Check for common extensions that can be handled in the browser control
                        foreach (string s in bypassList)
                        {
                            if (tempUri.OriginalString.EndsWith(s, StringComparison.OrdinalIgnoreCase))
                            {
                                this.ShowProgresBarOverlay();
                                handledExtension = true;
                                break;
                            }
                        }

                        if (!handledExtension)
                        {
                            // Are we launching a media file?
                            foreach (string s in mediaExtensions)
                            {
                                if (tempUri.LocalPath.EndsWith(s, StringComparison.OrdinalIgnoreCase))
                                {
                                    MediaPlayerLauncher mpl = new MediaPlayerLauncher();
                                    mpl.Media = tempUri;
                                    mpl.Show();
                                    mediaFileType = true;
                                    e.Cancel = true;
                                    this.HideOverlay();
                                    break;
                                }
                            }

                            if (!mediaFileType)
                            {
                                // If not, are we launching another type of file?
                                foreach (string s in launchExtensions)
                                {
                                    if (tempUri.OriginalString.EndsWith(s, StringComparison.OrdinalIgnoreCase))
                                    {
                                        Windows.System.Launcher.LaunchUriAsync(tempUri); // Launch the URI
                                        e.Cancel = true;
                                        this.HideOverlay();
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (!e.Cancel)
            {
                // Bug in WP8 SL WebBrowser control, it does not escape URI string before passing to external apps registered to handle
                // non-http protocols. 
                if (tempUri.Scheme == "mailto" || tempUri.Scheme == "tel")
                {
                    if (tempUri.Scheme == "tel" && (this.nonHttpUri == null || this.nonHttpUri.OriginalString != tempUri.OriginalString))
                    {
                        string trimmedUri = HttpUtility.UrlDecode(tempUri.AbsoluteUri);
                        trimmedUri = trimmedUri.Replace(" ", string.Empty);
                        this.nonHttpUri = new Uri(trimmedUri);
                        e.Cancel = true;
                        this.Browser.Navigate(this.nonHttpUri);
                    }

                    this.HideOverlay();
                }
            }
        }

        private void Browser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
        {
            // This condition is used for the scenario when the app is restored and this method is executed with an invalid e.Uri. In that scenario the OnNavigatedTo method was not called yet.
            if (!string.IsNullOrWhiteSpace(e.Uri.OriginalString))
            {
                this.currentUrl = e.Uri;
            }

            this.StartLoadCompleteSimulation();

            if (this.webConfig.Pin.IsEnabled)
            {
                // Disable pin icon on home screen
            if (currentUrl.OriginalString == this.webConfig.GetBaseUrl().OriginalString)
                ((ApplicationBarIconButton)ApplicationBar.Buttons[2]).IsEnabled = false;
            else
                //disable pin icon if already pinned.
                ((ApplicationBarIconButton)ApplicationBar.Buttons[2]).IsEnabled = (ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString().Contains("StartURL=" + this.currentUrl)) == null);
            }

        }

        private void StartLoadCompleteSimulation()
        {
            if (this.loadCompleteSimulationTimer == null)
            {
                this.loadCompleteSimulationTimer = new DispatcherTimer();
                this.loadCompleteSimulationTimer.Interval = new TimeSpan(0, 0, 0, 0, 100);
                this.loadCompleteSimulationTimer.Tick += this.LoadCompleteInjectLogic_Tick;
            }

            this.loadCompleteSimulationCounter = 0;
            this.loadCompleteSimulationTimer.Start();
        }

        private void LoadCompleteInjectLogic_Tick(object sender, EventArgs e)
        {
            try
            {
                var scriptString = "(function() {\n" +
                                        "var windowOnDOMContentLoaded = function (e){ \n" +
                                            "window.external.notify('onDOMContentLoaded~~' + window.location);\n" +
                                        "};\n" + // end of window.onDOMContentLoaded event listener

                                        "window.addEventListener ?" +
                                        "window.addEventListener('DOMContentLoaded', windowOnDOMContentLoaded, false) :" +
                                        "window.attachEvent && window.attachEvent('onDOMContentLoaded', windowOnDOMContentLoaded);\n" +
                                    "})();";

                this.Browser.InvokeScript("eval", scriptString);
            }
            catch (SystemException)
            {
                this.loadCompleteSimulationCounter++;

                if (this.loadCompleteSimulationCounter > 100)
                {
                    this.loadCompleteSimulationTimer.Stop();
                }

                return;
            }

            this.loadCompleteSimulationTimer.Stop();
        }

        private async void Browser_LoadCompleted(object sender, NavigationEventArgs e)
        {
            if (!this.isDomLoadedHandled)
            {
                RedirectModule.InjectRedirectRulesSpys(this.webConfig, this.Browser);

                if (this.webConfig.LocalXHRInterceptor != null)
                {
                    if (this.webConfig.LocalXHRInterceptor.IsEnabled)
                    {
                        string xhrScript = await UtilitiesModule.ReadScriptAsync("ms-appx:///XHR/injectedXHR.script");
                        Browser.InvokeScript("eval", xhrScript);

                        // Important:  This injection script will not always get called in time depending on how your web page 
                        // is implemented.  An alternative approach is to include the following script reference at the top
                        // of your locally wrapped website:
                        // <script type="text/javascript" src="../XHR/injectedXHR.script"></script>
                    }
                }

                // Inject custom CSS string
                var scriptString = this.webConfig.Styles.GetInvokeString();

                // InvokeScript to modify css. Need to do this on a per-page basis to improve perf
                this.Browser.TryToRunScript(scriptString);

                // Inject custom CSS file
                var stream = TitleContainer.OpenStream("Config/CssToInject.css");
                var streamReader = new StreamReader(stream);
                var cssToInject = await streamReader.ReadToEndAsync();
                if (!string.IsNullOrEmpty(cssToInject))
                {
                    string javascriptToInjectCss = string.Format("var cssToInject = document.createElement('style'); cssToInject.innerHTML = '{0}'; document.body.appendChild(cssToInject);", cssToInject.Replace("\n", string.Empty).Replace("\r", string.Empty));
                    this.Browser.TryToRunScript(javascriptToInjectCss);
                }

                // Remove the progress bar
                this.HideOverlay();

                this.isDomLoadedHandled = true;

                _activeNavigation = false;
            }
        }

        private void Browser_NavigationFailed(object sender, NavigationFailedEventArgs e)
        {

            // Remove the progress bar if we need to show an error message in the browser
            HideOverlay();

            // Display error to user if server or network error
            if (e.Uri != null && e.Uri.Scheme != "javascript" && !(_navigationAtDeactivation))
            {
                MessageBox.Show("An error has occured while loading new content. This could be due to network connectivity or server issue. Please check your network settings and try again.");
            }

            // Clear deactivation flag
            _navigationAtDeactivation = false;
        }


        #endregion

        private void Browser_ScriptNotify(object sender, NotifyEventArgs e)
        {
            var content = e.Value.Split(new string[] { "~~" }, StringSplitOptions.None);

            if (content.Length == 2)
            {
                if (RedirectModule.CheckForMessages(content, this.webConfig, this, this.webDialogOverlay))
                {
                    return;
                }

                if (content[0].Equals("BROWSERHIDEOVERLAY", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.HideOverlay();
                    return;
                }

                if (content[0].Equals("onDOMContentLoaded", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.Browser_LoadCompleted(this.Browser, new NavigationEventArgs(string.Empty, new Uri(content[1], UriKind.RelativeOrAbsolute)));
                    return;
                }
            }
            else
            {
                // if the local XHR injection has succeeded, it will fire through here for each XHR request made
                dynamic order = JsonConvert.DeserializeObject(e.Value);
                if (order != null)
                {
                    if (order.type == "XHR")
                    {
                        LocalXHRInterceptor.Intercept(order, Browser, null);
                    }
                }
            }
        }
    }
}